package com.lagou.filter;

import com.lagou.pojo.MethodTimeInfo;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Activate(group = {CommonConstants.CONSUMER})
public class TPMonitorFilter implements Filter, Runnable {

    // 每个方法耗时情况
    Map<String, List<MethodTimeInfo>> methodTimeMap = new HashMap<>();

    public  TPMonitorFilter(){
        // 每隔5秒打印一次最近一分钟内每个方法的TP90、TP99的耗时情况
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(this,1,5, TimeUnit.SECONDS);
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long   startTime  = System.currentTimeMillis();
        try {
            // 执行方法
            Result invoke = invoker.invoke(invocation);
            return invoke;
        } finally {

            // 结束时间
            long endTime = System.currentTimeMillis();
            // 耗时时间
            long serviceTime = endTime - startTime;

            // 组织方法调用情况
            MethodTimeInfo methodTimeInfo = new MethodTimeInfo();
            methodTimeInfo.setServiceTime(serviceTime);
            methodTimeInfo.setStartTime(startTime);

            // 方法名
            String methodName = invocation.getMethodName();

            List<MethodTimeInfo> methodTimeInfoList = methodTimeMap.get(methodName);
            // 第一次调用初始化
            if (methodTimeInfoList == null)
            {
                methodTimeInfoList = new ArrayList<>();
            }
            methodTimeInfoList.add(methodTimeInfo);
            methodTimeMap.put(methodName, methodTimeInfoList);
        }
    }

    @Override
    public void run() {

        // 当前时间
        long currentTime = System.currentTimeMillis();
        // 1分钟之前的时间
        long time1MinuteAgo = currentTime - 60000;

        // 打印内容
        StringBuilder stringBuilder = new StringBuilder();
        for (Map.Entry<String, List<MethodTimeInfo>> map : methodTimeMap.entrySet())
        {
            // 方法名
            String methodName = map.getKey();

            List<MethodTimeInfo> methodTimeInfoList = map.getValue();

            // 1分钟时间内调用方法的耗时记录
            List<Long> fServiceTimeList = new ArrayList<>();

            for (Iterator<MethodTimeInfo> iterator = methodTimeInfoList.iterator(); iterator.hasNext();)
            {
                MethodTimeInfo methodTimeInfo = iterator.next();

                if (methodTimeInfo.getStartTime() >= time1MinuteAgo)
                {
                    fServiceTimeList.add(methodTimeInfo.getServiceTime());
                }
                else
                {
                    // 1分钟之前的记录，清除
                    iterator.remove();
                }
            }

            // 正序排序
            fServiceTimeList.sort(Comparator.comparingLong(Long::longValue));

            // TP90
            int tp90 = (int) (fServiceTimeList.size()* 0.9);
            // TP99
            int tp99 = (int) (fServiceTimeList.size()* 0.99);
            stringBuilder.append(methodName + "：TP90 = " + fServiceTimeList.get(tp90)
                    + "毫秒，TP99 = " + fServiceTimeList.get(tp99) + "毫秒   ");
        }

        System.out.println(stringBuilder);
    }
}
